package com.example.business.controller;

import com.example.business.utils.JWTUtil;
import com.example.business.utils.QrCodeUtil;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Controller
@RequestMapping("/login")
public class QrCodeLoginController {
    // 注入缓存管理器（需在Spring配置类中配置缓存，如Caffeine、Redis等）
    @Resource
    private CacheManager cacheManager;

    // 跳转二维码登录页面
    @GetMapping("/qrPage")
    public String qrCodePage() {
        // 跳转到qr-login.html页面（需放在resources/static目录下）
        return "qr-login";
    }

    // SSE接口：推送动态二维码
    @GetMapping(path = "qrCode", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter qrCodeStream() throws IOException {
        // 1. 初始化SSE发射器，5分钟超时
        SseEmitter sseEmitter = new SseEmitter(5 * 60 * 1000L);
        // 当前有效的二维码ID（原子类保证线程安全）
        AtomicReference<String> currentQrCodeId = new AtomicReference<>();
        // 定时任务执行器（单线程）
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
            Thread thread = new Thread(runnable);
            thread.setDaemon(true); // 守护线程：主线程退出时自动销毁
            return thread;
        });

        // 2. 生成并推送二维码的任务
        Runnable refreshTask = () -> {
            try {
                // 生成新二维码ID
                String newQrCodeId = "952e5a31-4557-4da4-91d6-a88fc27e45e2";
                // 移除旧二维码缓存
                String oldQrCodeId = currentQrCodeId.getAndSet(newQrCodeId);
                if (oldQrCodeId != null) {
                    getQrCache().evict(oldQrCodeId);
                }

                // 生成二维码（内容为二维码ID，前端扫码后需将此ID发送给后端验证）
                String qrCodeBase64 = QrCodeUtil.generateQrCodeBase64(
                        newQrCodeId,  // 二维码内容（后续用于验证）
                        200,  // 宽度
                        200,  // 高度
                        Color.RED,  // 前景色
                        QrCodeUtil.DrawStyle.CIRCLE  // 样式
                );

                // 封装推送数据（Data URI格式，前端可直接作为img的src）
                Map<String, Object> data = new HashMap<>();
                data.put("qrCodeSrc", "data:image/jpeg;base64," + qrCodeBase64);
                data.put("message", "请扫描二维码登录（2分钟内有效）");

                // 缓存新二维码与SSE发射器的关联（用于后续扫码回调）
                getQrCache().put(newQrCodeId, new QrCodeInfo(sseEmitter, "UNSCANNED"));

                // 推送二维码更新事件
                sseEmitter.send(SseEmitter.event()
                        .name("qrCodeUpdate")  // 事件名：前端监听此事件
                        .data(data));

            } catch (Exception e) {
                // 发送失败（如前端已断开连接），清理资源
                scheduler.shutdownNow();
                cleanCache(currentQrCodeId.get());
            }
        };

        // 3. 立即执行首次推送，之后每2分钟刷新一次（避免二维码过期）
        scheduler.scheduleAtFixedRate(refreshTask, 0, 2, TimeUnit.MINUTES);

        // 4. SSE生命周期回调：清理资源
        sseEmitter.onTimeout(() -> handleCleanup(scheduler, currentQrCodeId.get()));
        sseEmitter.onError(e -> handleCleanup(scheduler, currentQrCodeId.get()));
        sseEmitter.onCompletion(() -> handleCleanup(scheduler, currentQrCodeId.get()));

        return sseEmitter;
    }

    // 移动端扫码后调用此接口（验证二维码并通知前端登录成功）
    @PostMapping("/qrCode/scan")
    @ResponseBody
    public Map<String, String> scanQrCode(@RequestParam String qrCodeId, @RequestParam("userId") String username) {
        Map<String, String> result = new HashMap<>();
        qrCodeId = "952e5a31-4557-4da4-91d6-a88fc27e45e2";
//        System.out.println(userId + qrCodeId);
        QrCodeInfo qrInfo = getQrCache().get(qrCodeId, QrCodeInfo.class);

        if (qrInfo == null || !"UNSCANNED".equals(qrInfo.getStatus())) {
            result.put("code", "400");
            result.put("msg", "二维码已过期或无效");
            return result;
        }

        try {
            // 1. 标记二维码状态为已扫描（实际业务中需验证userId合法性）
            qrInfo.setStatus("SCANNED");
            getQrCache().put(qrCodeId, qrInfo);

            // 2. 通过SSE通知前端：登录成功（可携带token等信息）
            Map<String, Object> loginData = new HashMap<>();
            loginData.put("code", "200");
            loginData.put("msg", "登录成功");
            loginData.put("token", JWTUtil.generateAccessToken(username));
            qrInfo.getSseEmitter().send(SseEmitter.event()
                    .name("loginSuccess")  // 登录成功事件
                    .data(loginData));

            result.put("code", "200");
            result.put("msg", "扫码成功，请在PC端确认");
        } catch (IOException e) {
            result.put("code", "500");
            result.put("msg", "通知PC端失败");
        }
        return result;
    }


    @PostMapping("/login/logout")
    @ResponseBody
    public Map<String, String> logout(HttpServletRequest request) {
        // 1. 从请求头获取token（实际项目中需验证token有效性）
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            // 2. 清除服务器端的token关联信息（如Redis中的用户状态）
            // redisTemplate.delete("login:token:" + token);
        }

        Map<String, String> result = new HashMap<>();
        result.put("code", "200");
        result.put("msg", "退出成功");
        return result;
    }

    // 工具方法：获取缓存
    private Cache getQrCache() {
        return cacheManager.getCache("qrCodeCache");
    }

    // 工具方法：清理缓存和定时任务
    private void handleCleanup(ScheduledExecutorService scheduler, String qrCodeId) {
        scheduler.shutdownNow();
        cleanCache(qrCodeId);
    }

    private void cleanCache(String qrCodeId) {
        if (qrCodeId != null) {
            getQrCache().evict(qrCodeId);
        }
    }

    // 内部类：存储二维码相关信息
    private static class QrCodeInfo {
        private SseEmitter sseEmitter;
        private String status; // UNSCANNED:未扫描 SCANNED:已扫描 EXPIRED:已过期

        public QrCodeInfo(SseEmitter sseEmitter, String status) {
            this.sseEmitter = sseEmitter;
            this.status = status;
        }

        // getter/setter
        public SseEmitter getSseEmitter() { return sseEmitter; }
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
    }
}